package com.wzx.core.utils;

import com.wzx.core.ioc.anootaction.Component;
import com.wzx.core.ioc.anootaction.Configuration;
import com.wzx.core.ioc.bean.BeanDefinition;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public class ClassUtil {

    /**
     * 判断当前类是否为Component
     * @param cls
     * @return
     */
    public static boolean isComponent(Class cls) {
        if (cls.isAnnotation()) {
            return false;
        }

        for (Annotation annotation : cls.getAnnotations()) {
            if (annotation instanceof Component) {
                return true;
            } else if (annotation.annotationType().isAnnotationPresent(Component.class)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取这个包下所有的类
     * @param packStr
     * @return
     */
    public static List<BeanDefinition> getAllClassForBeanDefinition(String packStr) {
        List<BeanDefinition> beanDefinitionList = new ArrayList<>();
        try {
            List<Class> allClass = getAllClass(packStr);
            for (Class cls : allClass) {
                if (isComponent(cls)) {
                    beanDefinitionList.add(BeanDefinition.newInstance(cls));
                }
                if (cls.isAnnotationPresent(Configuration.class)) {
                    beanDefinitionList.addAll(loadConfigurationClass(cls));
                }
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        return beanDefinitionList;
    }

    private static List<BeanDefinition> loadConfigurationClass(Class cls) {
        List<BeanDefinition> list = new ArrayList<>();
        try {
            Object o = cls.newInstance();
            for (Method method : cls.getDeclaredMethods()) {
                if (Modifier.isStatic(method.getModifiers())) {
                    continue;
                }
                Object bean = method.invoke(o);
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setBeanName(method.getName());
                beanDefinition.setOriginClass(bean.getClass());
                beanDefinition.setManualBean(bean);
                list.add(beanDefinition);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 获取这个包下所有的类
     * @param packStr
     * @return
     */
    public static List<Class> getAllClass(String packStr) throws URISyntaxException {
        ClassLoader classLoader = ClassUtil.class.getClassLoader();
        URL resource = classLoader.getResource("");

        Path path = Paths.get(resource.toURI());
        String packageDir = packStr.replaceAll("\\.", File.separator + File.separator);
        List<String> className = getClassName(path.resolve(packageDir), packStr);

        return className.stream().map(cls -> {
            try {
                return Class.forName(cls);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());
    }

    public static List<String> getClassName(Path classesDir, String packStr) {
        List<String> classNameList = new ArrayList<>();
        try {
            Files.newDirectoryStream(classesDir).forEach(item -> {
                if (Files.isDirectory(item)) {
                    String currDir = item.getFileName().toString();
                    classNameList.addAll(getClassName(classesDir.resolve(currDir), packStr + "." + currDir));
                    return;
                }
                String className = item.getFileName().toString();
                classNameList.add(packStr + "." + className.substring(0, className.indexOf(".")));
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classNameList;
    }

    public static String firstWordLower(String name) {
        return name.substring(0, 1).toLowerCase() + name.substring(1);
    }

    public static void main(String[] args) throws IOException, URISyntaxException {
        getAllClass("com.wzx");
    }
}
